在現代的 Web 應用開發中,有效管理全局狀態是一個關鍵挑戰。Nuxt3 作為一個強大的 Vue.js 框架,結合 Pinia 這個靈活的狀態管理庫,為開發者提供了一套完整的解決方案。本文將深入探討如何在 Nuxt3 中使用 Pinia 管理全局狀態,並整合其他先進的前端技術,如 Zod、Vee-Validate 和 VueUse,以構建一個健壯、高效的應用。
首先,我們需要安裝 Pinia 和其他相關的包:
bunx nuxi module add pinia
bunx nuxi module vee-validate
bunx nuxi module vueuse
bun add zod @vee-validate/zod @vueuse/core
在 stores
目錄下創建一個新的 store 文件,例如 userStore.ts
:
import * as zod from 'zod';
import { defineStore, acceptHMRUpdate } from 'pinia';
export const userSchema = zod.object({
id: zod.number(),
name: zod.string(),
email: zod.string().email(),
});
export type UserSchema = zod.infer<typeof userSchema>;
export const useBaseStore = defineStore('useBaseStore', () => {
// state::
const user = ref<UserSchema | null>(null);
// methods::
const fetchUser = async (): Promise<void> => {
const response = await $fetch('/api/user', {
method: 'GET',
});
const validator = userSchema.safeParse(response);
if (!validator.success) {
throw new TypeError('validator error');
}
user.value = validator.data;
};
const logout = (): void => {
user.value = null;
};
return {
// state::
user,
// methods::
fetchUser,
logout,
}
})
if (import.meta.hot) {
import.meta.hot.accept(acceptHMRUpdate(useBaseStore, import.meta.hot));
}
創建一個新的組件 UserProfile.vue
:
<template>
<div v-if="user">
<h2>Welcome, {{ user.name }}!</h2>
<p>Email: {{ user.email }}</p>
<button @click="logout">Logout</button>
</div>
<div v-else>
<p>Please log in</p>
</div>
</template>
<script setup lang="ts">
import { useUserStore } from '~/stores/userStore'
import { storeToRefs } from 'pinia'
const userStore = useUserStore()
const { user } = storeToRefs(userStore)
const { logout } = userStore
onMounted(async () => {
await userStore.fetchUser()
})
</script>
為了處理客戶端存儲,我們可以使用 VueUse 的 useLocalStorage
和 Nuxt3 的 useNuxtApp
:
import { defineStore } from 'pinia'
import { useLocalStorage } from '@vueuse/core'
export const useUserStore = defineStore('user', () => {
const nuxtApp = useNuxtApp()
const user = ref(null)
if (process.client) {
const storedUser = useLocalStorage('user', null)
watch(storedUser, (newValue) => {
user.value = newValue
})
}
async function fetchUser() {
const response = await nuxtApp.$fetch('/api/user')
user.value = response
if (process.client) {
localStorage.setItem('user', JSON.stringify(response))
}
}
return { user, fetchUser }
})
為了解決可能出現的 hydration 問題,我們可以使用 Nuxt3 的 <ClientOnly>
組件:
<template>
<ClientOnly>
<div v-if="user">
<h2>Welcome, {{ user.name }}!</h2>
<p>Email: {{ user.email }}</p>
</div>
<template #fallback>
<p>Loading user data...</p>
</template>
</ClientOnly>
</template>
在 Nuxt3 中使用 Pinia 管理全局狀態不僅提高了開發效率,還增強了應用的可維護性和可擴展性。通過整合 Zod 進行數據驗證、Vee-Validate 處理表單驗證,以及利用 VueUse 的 useLocalStorage
處理客戶端存儲,我們構建了一個強大而靈活的狀態管理系統。
需要特別注意的是在服務器端渲染(SSR)環境中處理客戶端特定的操作,如本地存儲。使用 Nuxt3 的 <ClientOnly>
組件和條件性的代碼執行可以有效解決 hydration 問題。
最後,使用 Nuxt 提供的 $fetch
方法進行 API 請求,進一步統一了我們的數據獲取策略。這種整合方法不僅簡化了開發流程,還提高了代碼的一致性和可讀性。
通過實施這些最佳實踐,開發者可以充分利用 Nuxt3 和 Pinia 的優勢,構建出高效、可靠且易於維護的現代 Web 應用。